/****************************************************************************
 * Copyright (C) 2009-2010 SciTouch LLC
 * 
 * This file is part of Indigo toolkit.
 * 
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 3 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 ***************************************************************************/

#ifndef __render_context_h__
#define __render_context_h__

#include <cairo.h>
#include <cairo-pdf.h>
#include <cairo-svg.h>

#include "render_common.h"

class RenderContext 
{
public:
   DEF_ERROR("render context");

   const HighlightingOptions* _hlOpt;
   const RenderContextOptions* _rcOpt;

   void checkPathNonEmpty () const;

   RenderContext ();
   void setScaleFactor (float sf);
   void setHDC (PVOID hdc);
   void setMode (DINGO_MODE mode);
   void setBaseColor (const Vec3f& c);
   int  getMaxPageSize () const;
   void setLineWidth (double width);
   void setFontFamily (const char* ff);
   void setOutput (Output* output);
   void setHighlightingOptions (const HighlightingOptions* hlOpt);
   void setRenderContextOptions (const RenderContextOptions* rcOpt);
   void createSurface();
   void init();
   void setBackground(const Vec3f& color);
   void fillBackground();
   void initContext (int width, int height);   
   void closeContext ();
   void translate (float dx, float dy);
   void scale (float sx, float sy);
   void storeTransform ();
   void restoreTransform ();
   void resetTransform ();
   void removeStoredTransform ();
   void drawRectangle (const Vec2f& p, const Vec2f& sz);
   void drawItemBackground (const RenderItem& item);
   void drawTextItemText (const TextItem& ti);
   void drawTextItemText (const TextItem& ti, const Vec3f& color, bool bold);
   void drawLine (const Vec2f& v0, const Vec2f& v1);
   void fillQuad (const Vec2f& v0, const Vec2f& v1, const Vec2f& v2, const Vec2f& v3);
   void drawQuad (const Vec2f& v0, const Vec2f& v1, const Vec2f& v2, const Vec2f& v3);
   void drawTriangle (const Vec2f& v0, const Vec2f& v1, const Vec2f& v2);
   void drawTriangleZigzag (const Vec2f& v0, const Vec2f& v1, const Vec2f& v2, int cnt);
   void drawTriangleStripes (const Vec2f& v0, const Vec2f& v1, const Vec2f& v2, int cnt);
   void drawCircle (const Vec2f& center, const float r);
   void fillCircle (const Vec2f& center, const float r);
   void drawArc (const Vec2f& center, const float r, const float a0, const float a1);
   void drawPoly (const Array<Vec2f>& v);
   void setFontSize (double fontSize);
   void setTextItemSize (TextItem& ti);
   void setTextItemSize (TextItem& ti, const Vec2f& c);
   void setGraphItemSizeDot (GraphItem& gi);
   void setGraphItemSizeCap (GraphItem& gi);
   void setGraphItemSizeSign (GraphItem& gi, GraphItem::TYPE type);
   void drawGraphItem (GraphItem& gi);
   void fillRect (double x, double y, double w, double h);
   void getColor (float& r, float& g, float& b, int c);
   int getElementColor (int label);
   void getColorVec (Vec3f& v, int color);
   void setSingleSource (int color);
   void setSingleSource (const Vec3f& color);
   float _getDashedLineAlignmentOffset (float length);
   void setDash (const Array<double>& dash, float offset = 0);
   void resetDash ();
   void setCapParam (float hc, float lw, float w);
   void setDotParam (float r);
   void setSignParam (float digitwidth, float digitheight, float linewidth);
   void drawPlus (const Vec2f& pos, const float linewidth, const float size);
   void drawEquality (const Vec2f& pos, const float linewidth, const float size, const float interval);
   void drawArrow (const Vec2f& p1, const Vec2f& p2, const float width, const float headwidth, const float headsize);
   float highlightedBondLineWidth () const;
   float currentLineWidth () const;
   void setHighlight();
   void resetHighlight();
   void resetHighlightThickness();   

   const RenderSettings& getRenderSettings () const {return _settings;}
   int getWidth() const {return _width;}
   int getHeight() const {return _height;}

   void initMetaSurface();
   void destroyMetaSurface();
   void getTextSize(Vec2f& sz, Vec2f& r, FONT_SIZE fontSize, const char* text);

   void cairoCheckStatus () const;
#ifdef _WIN32
   cairo_surface_t* createWin32Surface ();
   cairo_surface_t* createWin32PrintingSurfaceForHDC ();
   cairo_surface_t* createWin32PrintingSurfaceForMetafile (bool& isLarge);
   void storeAndDestroyMetafile ();
#endif

   void fontsClear();
   void fontsInit();
   void fontsDispose();
   void fontsSetFont(cairo_t* cr, FONT_SIZE size, bool bold);
   void fontsGetTextExtents(cairo_t* cr, const char* text, int size, float& dx, float& dy, float& rx, float& ry);
   void fontsDrawText(const TextItem& ti, const Vec3f& color, bool bold);

private:
   static cairo_status_t writer (void *closure, const unsigned char *data, unsigned int length);

   void lineTo (const Vec2f& v);
   void lineToRel (float x, float y);
   void lineToRel (const Vec2f& v);
   void moveTo (const Vec2f& v);
   void moveToRel (float x, float y);
   void moveToRel (const Vec2f& v);

   float _graphItemDotRadius;
   float _graphItemCapSlope;
   float _graphItemCapBase;
   float _graphItemCapWidth;
   float _graphItemDigitWidth;
   float _graphItemDigitHeight;
   float _graphItemSignLineWidth;
   float _graphItemPlusEdge;

   int _width;
   int _height;
   Vec3f _backColor;
   Vec3f _baseColor;
   float _currentLineWidth;

   class TextLock {
   public:
      TextLock () {
#ifdef _WIN32
         osMutexCreate(&_mutex);
#endif
      }

      ~TextLock () {
#ifdef _WIN32
         osMutexDelete(&_mutex);
#endif
      }

      void lock () {
#ifdef _WIN32
         osMutexLock(&_mutex);
#endif
      }

      void unlock () {
#ifdef _WIN32
         osMutexUnlock(&_mutex);
#endif
      }

   private:
#ifdef _WIN32
      os_mutex _mutex;
#endif
   };

   static TextLock _tlock;

   RenderSettings _settings;
   TL_CP_DECL(Array<char>, _fontfamily);
   TL_CP_DECL(Array<cairo_matrix_t>, transforms);
#ifdef _WIN32
   void* _h_fonts[FONT_SIZE_COUNT * 2];
#endif

   cairo_font_face_t *cairoFontFaceRegular, *cairoFontFaceBold;
   cairo_matrix_t fontScale, fontCtm;
   cairo_font_options_t *fontOptions;    
   cairo_scaled_font_t *_scaled_fonts[FONT_SIZE_COUNT * 2];

   cairo_t* _meta_cr;
   cairo_surface_t* _meta_surface;

   bool metafileFontsToCurves;
   cairo_t* _cr;
   cairo_surface_t* _surface;
   Output *_output;
   PVOID _hdc;
   DINGO_MODE _mode;
};

#endif
